package com.xqboss.apps.service.synthesis;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xqboss.apps.domain.box.Box;
import com.xqboss.apps.domain.nft.Nft;
import com.xqboss.apps.domain.synthesis.*;
import com.xqboss.apps.dto.PageDto;
import com.xqboss.apps.dto.synthesis.*;
import com.xqboss.apps.enums.synthesis.SynthesisTypeEnum;
import com.xqboss.apps.mapper.box.BoxMapper;
import com.xqboss.apps.mapper.nft.NftMapper;
import com.xqboss.apps.mapper.synthesis.*;
import com.xqboss.apps.vo.synthesis.SynthesisPlanConsumeDetailVo;
import com.xqboss.apps.vo.synthesis.SynthesisPlanPageConfigVo;
import com.xqboss.apps.vo.synthesis.SynthesisPlanPageVo;
import com.xqboss.common.exception.ServiceException;
import com.xqboss.common.utils.TransactionalManage;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * 合成方案 服务实现类
 * </p>
 *
 * @author 木鱼
 * @since 2023-11-17
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class SynthesisPlanService extends ServiceImpl<SynthesisPlanMapper, SynthesisPlan> {
    private final SynthesisPlanConsumeMapper synthesisPlanConsumeMapper;
    private final SynthesisPlanConsumeService synthesisPlanConsumeService;
    private final SynthesisPlanResultMapper synthesisPlanResultMapper;
    private final SynthesisPlanResultService synthesisPlanResultService;
    private final SynthesisPlanConsumeGroupMapper synthesisPlanConsumeGroupMapper;
    private final SynthesisPlanConsumeGroupService synthesisPlanConsumeGroupService;
    private final NftMapper nftMapper;
    private final BoxMapper boxMapper;
    private final TransactionalManage transactionalManage;

    public List<SynthesisPlanPageVo> selectBasicList(PageDto baseRequest, String name) {
        baseRequest.startPage();
        List<SynthesisPlanPageVo> synthesisPlanPageVos = baseMapper.selectBasicPage(name);
        // 列表数据需二次查询消耗、产出数据
        for (SynthesisPlanPageVo synthesisPlanPageVo : synthesisPlanPageVos) {
            // 查询消耗列表 并转成List<List>格式
            List<SynthesisPlanPageConfigVo> synthesisPlanPageConfigVos = synthesisPlanConsumeMapper.selectBasicList(synthesisPlanPageVo.getId());
            Map<Long, List<SynthesisPlanPageConfigVo>> collect = synthesisPlanPageConfigVos.stream().collect(Collectors.groupingBy(SynthesisPlanPageConfigVo::getGroupId));
            synthesisPlanPageVo.setConsumeList(new ArrayList<>(collect.values()));
            // 查询产出list
            synthesisPlanPageVo.setResultList(synthesisPlanResultMapper.selectBasicList(synthesisPlanPageVo.getId()));
        }
        return synthesisPlanPageVos;
    }

    public SynthesisPlanDetailDto selectByIdBasic(Long id) {
        SynthesisPlan synthesisPlan = baseMapper.selectById(id);
        if (synthesisPlan == null) {
            throw new ServiceException("方案不存在");
        }
        SynthesisPlanDetailDto resultDto = SynthesisPlanDetailDto.builder().id(synthesisPlan.getId()).name(synthesisPlan.getName()).build();
        // 查询消耗列表 并转成List<List>格式
        List<SynthesisPlanConsumeDto> synthesisPlanConsumeDtos = synthesisPlanConsumeMapper.selectDetailList(id);
        Map<Long, List<SynthesisPlanConsumeDto>> collect = synthesisPlanConsumeDtos.stream().collect(Collectors.groupingBy(SynthesisPlanConsumeDto::getGroupId));
        resultDto.setConsumes(new ArrayList<>(collect.values()));
        // 查询产出list
        resultDto.setResults(getPlanResult(id));
        return resultDto;
    }

    /**
     * 获取规则结果
     *
     * @param planId
     * @return
     */
    public List<SynthesisPlanResultDto> getPlanResult(Long planId){
        return synthesisPlanResultMapper.selectDetailList(planId);
    }

    public boolean updatePlan(SynthesisPlanUpdateDto record) {
        SynthesisPlan synthesisPlan = new SynthesisPlan();
        synthesisPlan.setId(record.getId());
        if (record.getUpdateType() == 1) {
            if (StrUtil.isBlank(record.getName())) {
                throw new ServiceException("方案名称不合法");
            }
            synthesisPlan.setName(record.getName());
            baseMapper.updateById(synthesisPlan);
        } else if (record.getUpdateType() == 2) {
            if (record.getDetailId() == null) {
                throw new ServiceException("明细id不可为空");
            }
            Assert.notNull(record.getNum(), "数量不合法");
            synthesisPlanConsumeMapper.update(null, Wrappers.<SynthesisPlanConsume>lambdaUpdate()
                    .eq(SynthesisPlanConsume::getId, record.getDetailId())
                    .eq(SynthesisPlanConsume::getPlanId, record.getId())
                    .set(SynthesisPlanConsume::getNum, record.getNum())
                    .set(SynthesisPlanConsume::getDurableThreshold, record.getDurableThreshold())
                    .set(SynthesisPlanConsume::getBreakageThreshold, record.getBreakageThreshold())
                    .set(SynthesisPlanConsume::getLevelThreshold, record.getLevelThreshold())
                    .set(SynthesisPlanConsume::getMinLevel, record.getMinLevel())
                    .set(SynthesisPlanConsume::getMaxLevel, record.getMaxLevel())
                    .set(SynthesisPlanConsume::getMinDurable, record.getMinDurable())
                    .set(SynthesisPlanConsume::getMaxDurable, record.getMaxDurable())
                    .set(SynthesisPlanConsume::getMinBreakage, record.getMinBreakage())
                    .set(SynthesisPlanConsume::getMaxBreakage, record.getMaxBreakage())

            );
        } else if (record.getUpdateType() == 3) {
            if (record.getDetailId() == null) {
                throw new ServiceException("明细id不可为空");
            }
            Assert.notNull(record.getNum(), "数量不合法");
            synthesisPlanResultMapper.update(null, Wrappers.<SynthesisPlanResult>lambdaUpdate()
                    .eq(SynthesisPlanResult::getId, record.getDetailId())
                    .eq(SynthesisPlanResult::getPlanId, record.getId())
                    .set(SynthesisPlanResult::getProductNum, record.getNum())
            );
        }
        return true;
    }

//    public boolean updateStock(SynthesisPlanStockDto record) throws Exception {
//        SynthesisPlanResult result = synthesisPlanResultMapper.selectById(record.getResultId());
//        Assert.notNull(result, "产出不存在");
//        Assert.isTrue(result.getType().getValue() == 2, "产出类型为nft才需要调整库存");
//        if (record.getType() == 1) {
//            transactionalManage.executeWithException(() -> {
//                boolean res = nftMapper.update(null,
//                        Wrappers.<Nft>lambdaUpdate()
//                                .setSql(" stock = stock - " + record.getNum())
//                                .setSql(" lock_stock = lock_stock + " + record.getNum())
//                                .eq(Nft::getId, result.getThirdId())
//                                .ge(Nft::getStock, record.getNum())
//                ) > 0;
//                Assert.isTrue(res, String.format("nft:%s,库存不足", result.getThirdId()));
//                synthesisPlanResultMapper.update(null, Wrappers.<SynthesisPlanResult>lambdaUpdate()
//                        .eq(SynthesisPlanResult::getId, record.getResultId())
//                        .setSql("num = num + " + record.getNum()));
//                return true;
//            });
//        } else if (record.getType() == 2) {
//            transactionalManage.executeWithException(() -> {
//                boolean res = nftMapper.update(null,
//                        Wrappers.<Nft>lambdaUpdate()
//                                .setSql(" stock = stock + " + record.getNum())
//                                .setSql(" lock_stock = lock_stock - " + record.getNum())
//                                .eq(Nft::getId, result.getThirdId())
//                                .ge(Nft::getLockStock, record.getNum())
//                ) > 0;
//                Assert.isTrue(res, String.format("nft:%s,锁定库存不足，请联系管理员", result.getThirdId()));
//                synthesisPlanResultMapper.reduceStock(record.getResultId(), record.getNum());
//                return true;
//            });
//        }
//        return true;
//    }

    public boolean saveBasic(SynthesisPlanDetailDto record) throws Exception {
        SynthesisPlan synthesisPlan = new SynthesisPlan();
        synthesisPlan.setName(record.getName());
        // 初始化消费实体
        List<List<SynthesisPlanConsume>> consumeList = buildConsumes(record);
        // 初始化产出实体
        List<SynthesisPlanResult> resultList = buildResults(record);
        transactionalManage.executeWithException(() -> {
            baseMapper.insert(synthesisPlan);
            for (List<SynthesisPlanConsume> consumes : consumeList) {
                SynthesisPlanConsumeGroup synthesisPlanConsumeGroup = SynthesisPlanConsumeGroup.builder()
                        .planId(synthesisPlan.getId())
                        .build();
                synthesisPlanConsumeGroupMapper.insert(synthesisPlanConsumeGroup);
                for (SynthesisPlanConsume consume : consumes) {
                    consume.setPlanId(synthesisPlan.getId());
                    consume.setGroupId(synthesisPlanConsumeGroup.getId());
                    synthesisPlanConsumeMapper.insert(consume);
                }
            }
            for (SynthesisPlanResult result : resultList) {
                result.setPlanId(synthesisPlan.getId());
                //合成结果需要扣除-nft对应库存（活动配置是统一处理）
//                if (SynthesisTypeEnum.EQUIPMENT == result.getType() || SynthesisTypeEnum.NORMAL == result.getType()) {
//                    boolean res = nftMapper.update(null,
//                            Wrappers.<Nft>lambdaUpdate()
//                                    .setSql(" stock = stock - " + result.getNum())
//                                    .setSql(" lock_stock = lock_stock + " + result.getNum())
//                                    .eq(Nft::getId, result.getThirdId())
//                                    .ge(Nft::getStock, result.getNum())
//                    ) > 0;
//                    Assert.isTrue(res, String.format("nft:%s,库存不足", result.getThirdId()));
//                }
                synthesisPlanResultMapper.insert(result);
            }
            return true;
        });
        return true;
    }

    public boolean removeBasic(WebSynthesisPlanDelDto params) throws Exception {
        Long id = params.getId();
        SynthesisPlan synthesisPlan = baseMapper.selectById(id);
        if (synthesisPlan == null) {
            throw new ServiceException("合成方案不存在");
        }
        if (params.getUpdateType() == 2) {
            SynthesisPlanConsume consume = synthesisPlanConsumeMapper.selectById(params.getDetailId());
            synthesisPlanConsumeMapper.deleteById(params.getDetailId());
            // 如果方案组内消耗已经全部已经删除，则方案组也同步删除
            if(Objects.nonNull(consume)){
                // 计算方案组内剩余的消耗数量
                Long l = synthesisPlanConsumeMapper.selectCount(Wrappers.<SynthesisPlanConsume>lambdaQuery().eq(SynthesisPlanConsume::getGroupId, consume.getGroupId()));
                if(l <= 0){
                    // 如果方案组内已经没有了消耗数量，则删除方案组
                    synthesisPlanConsumeGroupService.removeById(consume.getGroupId());
                }
            }
        } else if (params.getUpdateType() == 1) {
            baseMapper.deleteById(id);
        } else if (params.getUpdateType() == 3) {
            synthesisPlanResultMapper.deleteById(params.getDetailId());
        }
        return true;
    }

    /**
     * 初始化消耗实体
     */
    private List<List<SynthesisPlanConsume>> buildConsumes(SynthesisPlanDetailDto record) {
        List<List<SynthesisPlanConsume>> consumeList = new ArrayList<>();
        // 初始化消费实体
        for (List<SynthesisPlanConsumeDto> consume : record.getConsumes()) {
            List<SynthesisPlanConsume> detailList = new ArrayList<>();
            for (SynthesisPlanConsumeDto synthesisPlanConsumeDto : consume) {
                Assert.isFalse((synthesisPlanConsumeDto.getType().getValue() == 2 || synthesisPlanConsumeDto.getType().getValue() == 1 || synthesisPlanConsumeDto.getType().getValue() == 3)
                                && (ObjectUtil.isNull(synthesisPlanConsumeDto.getThirdId()) || synthesisPlanConsumeDto.getThirdId() < 0),
                        "消耗藏品id不合法");
                detailList.add(SynthesisPlanConsume.builder()
                        .type(synthesisPlanConsumeDto.getType())
                        .name(synthesisPlanConsumeDto.getName())
                        .imgUrl(synthesisPlanConsumeDto.getImgUrl())
                        .durableThreshold(synthesisPlanConsumeDto.getDurableThreshold())
                        .breakageThreshold(synthesisPlanConsumeDto.getBreakageThreshold())
                        .levelThreshold(synthesisPlanConsumeDto.getLevelThreshold())
                        .minDurable(synthesisPlanConsumeDto.getMinDurable())
                        .maxDurable(synthesisPlanConsumeDto.getMaxDurable())
                        .minBreakage(synthesisPlanConsumeDto.getMinBreakage())
                        .maxBreakage(synthesisPlanConsumeDto.getMaxBreakage())
                        .minLevel(synthesisPlanConsumeDto.getMinLevel())
                        .maxLevel(synthesisPlanConsumeDto.getMaxLevel())
                        .thirdId(synthesisPlanConsumeDto.getThirdId())
                        .num(synthesisPlanConsumeDto.getNum())
                        .planId(record.getId())
                        .groupId(synthesisPlanConsumeDto.getGroupId())
                        .build());
            }
            consumeList.add(detailList);
        }
        return consumeList;
    }

    /**
     * 初始化产出实体
     */
    private List<SynthesisPlanResult> buildResults(SynthesisPlanDetailDto record) {
        List<SynthesisPlanResult> resultList = new ArrayList<>();
        // 初始化产出实体
        for (SynthesisPlanResultDto result : record.getResults()) {
            //校验藏品/装备/宝盒发放数量 <= 剩余库存
            Integer productNum = result.getProductNum().intValue();
            if (result.getType() == SynthesisTypeEnum.NORMAL || result.getType() == SynthesisTypeEnum.EQUIPMENT) {
                Nft nft = nftMapper.selectNftById(result.getThirdId());
                if (productNum > nft.getStock()) {
                    throw new ServiceException("方案结果：" + result.getName() + "发放数量超过库存");
                }
                result.setProductNum(BigDecimal.valueOf(productNum));
            } else if (result.getType() == SynthesisTypeEnum.BOX) {
                Box box = boxMapper.selectById(result.getThirdId());
                if (productNum > box.getStock()) {
                    throw new ServiceException("方案结果：" + result.getName() + "发放数量超过库存");
                }
                result.setProductNum(BigDecimal.valueOf(productNum));
            }
            resultList.add(SynthesisPlanResult.builder()
                    .planId(record.getId())
                    .type(result.getType())
                    .name(result.getName())
                    .imgUrl(result.getImgUrl())
                    .thirdId(result.getThirdId())
                    .productNum(result.getProductNum())
                    .num(result.getNum())
                    .build());
        }
        return resultList;
    }

    /**
     * 获取活动的所有方案消耗列表
     *
     * @param planId
     * @return
     */
    public List<SynthesisPlanConsumeDetailVo> selectSynthesisPlanConsumeList(Long planId) {

        return null;
    }

    /**
     * 获取活动的所有方案消耗列表
     *
     * @param planId
     * @return
     */
    public List<SynthesisPlanResultDto> selectSynthesisPlanResultList(Long planId) {
        return null;
    }

    /**
     * 编辑规则
     *
     * @param params
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean edit(WebSynthesisConsumeEditDto params) {
        if (Objects.isNull(params) || params.getId() == null) {
            throw new ServiceException("参数错误");
        }
        SynthesisPlan plan = new SynthesisPlan();
        plan.setId(params.getId());
        plan.setName(params.getName());
        //编辑规则方案
        updateById(plan);


        //编辑方案-消耗
        for (WebSynthesisPlanConsumeEditDto maxConsume : params.getMaxConsumes()) {
            if (maxConsume.getGroupId() != null) { //编辑
                List<SynthesisPlanConsumeDto> dtoConsume = maxConsume.getConsumes();
                for (SynthesisPlanConsumeDto it : dtoConsume) {
                    SynthesisPlanConsume con = new SynthesisPlanConsume();
                    con.setId(it.getConsumeId());
                    con.setPlanId(params.getId());
                    con.setGroupId(maxConsume.getGroupId());
                    con.setName(it.getName());
                    con.setImgUrl(it.getImgUrl());
                    con.setType(it.getType());
                    con.setThirdId(it.getThirdId());
                    con.setNum(it.getNum());
                    con.setDurableThreshold(it.getDurableThreshold());
                    con.setBreakageThreshold(it.getBreakageThreshold());
                    con.setLevelThreshold(it.getLevelThreshold());
                    con.setMinDurable(it.getMinDurable());
                    con.setMaxDurable(it.getMaxDurable());
                    con.setMinBreakage(it.getMinBreakage());
                    con.setMaxBreakage(it.getMaxBreakage());
                    con.setMinLevel(it.getMinLevel());
                    con.setMaxLevel(it.getMaxLevel());
                    synthesisPlanConsumeService.saveOrUpdate(con);
                }
            } else {
                SynthesisPlanConsumeGroup group = SynthesisPlanConsumeGroup.builder()
                        .planId(params.getId())
                        .build();
                synthesisPlanConsumeGroupMapper.insert(group);
                for (SynthesisPlanConsumeDto item : maxConsume.getConsumes()) {
                    SynthesisPlanConsume synConsume = BeanUtil.copyProperties(item, SynthesisPlanConsume.class);
                    synConsume.setId(item.getConsumeId());
                    synConsume.setPlanId(params.getId());
                    synConsume.setGroupId(group.getId());
                    synthesisPlanConsumeService.saveOrUpdate(synConsume);
                }
            }
        }


        //编辑方案结果
        if (CollUtil.isNotEmpty(params.getResults())) {
            List<SynthesisPlanResultDto> dtoResult = params.getResults();
//            for (SynthesisPlanResultDto res : dtoResult) {
//                SynthesisPlanResult result = new SynthesisPlanResult();
//                result.setId(res.getResultId());
//                result.setPlanId(params.getId());
//                result.setName(res.getName());
//                result.setImgUrl(res.getImgUrl());
//                result.setType(res.getType());
//                result.setThirdId(res.getThirdId());
//                result.setProductNum(res.getProductNum());
//                result.setNum(res.getNum());
//                result.setLockNum(res.getLockNum());
//                result.setNowNum(result.getNowNum());
//                synthesisPlanResultService.saveOrUpdate(result);
//            }
            for (SynthesisPlanResultDto result : dtoResult) {
                SynthesisPlanResult res = BeanUtil.copyProperties(result, SynthesisPlanResult.class);
                res.setId(result.getResultId());
                res.setPlanId(params.getId());
                synthesisPlanResultService.saveOrUpdate(res);
            }
        }
        return true;
    }
}